﻿using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Serilog;
using Serilog.Events;
using System.Text;
using System.Text.Json.Serialization;
using ZhiJiao.Dal;
using ZhiJiao.Models.Entities;
using ZhiJiao.Service.Abstracts;
using ZhiJiao.Service.Dto;
using ZhiJiao.Service.Profiles;
using ZhiJiao.Service.Services;

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;

// 请求上下文访问器服务
builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<BackJson>();
builder.Services.AddTransient<IAccountService, AccountService>();
builder.Services.AddTransient<IRoleService, RoleService>();
builder.Services.AddTransient<IInstructionService, InstructionService>();
builder.Services.AddTransient<IModuleService, ModuleService>();
builder.Services.AddTransient<ICurrentUser, CurrentUser>();
builder.Services.AddTransient<IHomeService, HomeService>();
builder.Services.AddTransient<IEvaluationService,EvaluationService>();
builder.Services.AddTransient<IFileUploadService, FileUploadService>();
builder.Services.AddTransient<IRuleService, RuleService>();
builder.Services.AddTransient<ICourseService, CourseService>();

// 服务注册
builder.Services.AddControllersWithViews()
                .AddJsonOptions(options => {
                    options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; // 序列化时忽略循环引用
                    options.JsonSerializerOptions.MaxDepth = 64;  // 序列化最大深度(可选)
                });

//数据库上下文, 包含其他Entity实体数据库上下文
builder.Services.AddDbContext<ZJDbContext>(p =>
{
    p.UseSqlServer(builder.Configuration["ConnectionString:SqlServer"], b => b.MigrationsAssembly("ZHIJIAO"));
});

// AutoMapper 映射服务
builder.Services.AddAutoMapper(config =>{
    config.AddProfile<ZJProfile>(); // 添加映射档案
});



// 注册Identity中，"用户"和"角色"服务
builder.Services.AddIdentity<User, Role>()
    .AddEntityFrameworkStores<ZJDbContext>();

// Identity 配置(密码格式要求，账户锁定设置，)
// 这些配置是最全的了
builder.Services.Configure<IdentityOptions>(option =>
{
    option.Password.RequireDigit = false; // 密码中必须含有数字
    option.Password.RequiredLength = 3;   // 密码最小长度，默认为6
    option.Password.RequiredUniqueChars = 1;  // 密码必须包含的唯一字符的最小数目，默认值为1
    option.Password.RequireLowercase = false;  // 该值指示师傅必须包含小写ASCII字符，默认为true
    option.Password.RequireUppercase = false;  // 该值指示密码是否必须包含大写ASCII字符，默认为true
    option.Password.RequireNonAlphanumeric = false; // 该值指示密码是否必须包含非字符数字字符，默认为true

    // 设置 TimeSpan 用户在锁定时被锁定。 默认为 5 分钟。
    option.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    // 该值指示是否可以锁定新用户。默认值为 true。
    option.Lockout.AllowedForNewUsers = false;
    // 设置在用户锁定之前允许的失败访问尝试次数，前提是已启用锁定。 默认值为 5。
    option.Lockout.MaxFailedAccessAttempts = 5;
    // 用户是否需要唯一的电子邮件。 默认为 false。
    option.User.RequireUniqueEmail = false;
    // 设置用户名中用于验证用户名的允许字符列表,默认为 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+
    option.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";


    // 该值指示是否需要确认 IUserConfirmation<TUser> 的帐户登录。 默认为 false。
    option.SignIn.RequireConfirmedAccount = false;
    // 该值指示是否需要确认的电子邮件地址登录。 默认为 false。
    option.SignIn.RequireConfirmedEmail = false;
    // 该值指示是否需要确认的电话号码登录。 默认为 false。
    option.SignIn.RequireConfirmedPhoneNumber = false;
});

builder.Services.ConfigureApplicationCookie(options =>
{
    // 设置 Cookie 过期时间为 30 分钟
    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);

    // 可选配置
    options.LoginPath = "/Account/Login";
    //options.LogoutPath = "/Identity/Account/Logout";
    //options.AccessDeniedPath = "/Identity/Account/AccessDenied";
});

// 认证服务
builder.Services.AddAuthentication()
        .AddCookie();

// 授权服务  此处添加授权策略
builder.Services.AddAuthorization();

// Serilog 从配置文件读取
builder.Host.UseSerilog((hostBuilderContext, loggerConfigration) =>
{
    loggerConfigration.ReadFrom.Configuration(hostBuilderContext.Configuration);


    // 非配置文件方式
    // 不从配置文件加载Serilog配置
    loggerConfigration.WriteTo.Console()
    .WriteTo.File($"{builder.Environment.ContentRootPath}/logs/yubing.log",
                   rollingInterval: RollingInterval.Day,
                   outputTemplate: "{Timestamp:HH:mm:ss fff zzz} " +  // 时间戳格式
                                   " || {Level} " +                    // Level:日志级别
                                " || {SourceContext:1} " +          //SourceContext：日志上下文
                                " || {Message} " +                  // Message：日志内容
                                " || {Exception} " +                // Exception：异常信息
                                " || end {NewLine}"                  //end:结束标志 NewLine：换行
                  )
    // 日志登记过滤
    .MinimumLevel.Information() // 设置最小级别
    .MinimumLevel.Override("Default", LogEventLevel.Information) // 默认设置
    .MinimumLevel.Override("Microsoft", LogEventLevel.Error) // 只输出微软的错误日志
    // 声明周期日志
    .MinimumLevel.Override("Default.Hosting.Lifetime", LogEventLevel.Information)
    .Enrich.FromLogContext();  // 将日志上下文也记录到日志中
});

// 配置AutoMapper
builder.Services.AddAutoMapper(cfg =>
{
    cfg.AddMaps(new string[] { "ZhiJiao.Service" }); // 通过 
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// 认证中间件
app.UseAuthentication();

// 授权中间件
app.UseAuthorization();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
